import { ElMessage } from 'element-plus';
import config from '@/config';
import { cryptoDecrypt, snakeCaseToCamelCase, camelCaseToSnakeCase } from '@/utils';
import { useAuthStore } from '@/stores/auth';
import { appLoginOutHandler } from '@/modules/app-gateway';

export const controllerList: any[] = [];

// 处理请求取消
const cancelRequest = (config: any) => {
  const controller = new AbortController();
  config.signal = controller.signal;
  controllerList.push(controller);
};

// 解码函数
const decode = (data: any, response: any) => {
  const url = response['config']['url'].split('?');
  const result = cryptoDecrypt(url[0], data);
  return result;
};

// 判断请求是否失败，若失败则返回理由
// 此方法只用于响应拦截器中，因此默认逻辑层请求成功，即不考虑http status为非200的情况
const requestFailed = (response: any) => {
  // 文件下载的情况，直接判定为请求成功
  const isBlob = response['data'] instanceof Blob;
  if (isBlob) {
    return [false];
  }

  const { code, message, success } = response['data'];
  // 默认一定会返回code，一般情况下code为200一定意味着请求成功
  if (code !== 200) {
    return [true, message];
  }

  // 承接上文，除非有特殊情况额外用success表示成功失败
  if (typeof success !== 'undefined' && !success) {
    return [true, message || '网络不佳,请刷新后重试'];
  }

  return [false];
};

// 获取响应码
const getErrorCode = (err: any) => {
  // 若应有层有返回，则使用应用层的
  if (err.response?.data?.code) {
    return err.response?.data?.code;
  }
  // 否则返回协议层的
  return err.response?.status;
};

// 是否可以提示异常
const canTip = (config: any) => {
  return config.noErrorTip !== true;
};

// 提示错误
const tip = (msg: string) => {
  ElMessage.error({
    message: msg,
    duration: 3000
  });
};

const formatHandler = {
  request: {
    onFulfilled: (request: any) => {
      // 处理请求头
      const authStore = useAuthStore();
      const hasToken = authStore.token;
      const notLoginUrl = request.url !== '/passport/login/username';
      // 具备token，且请求的接口不能是登录接口本身（因为后端未做限制）
      if (hasToken && notLoginUrl && !request.noToken) {
        request.headers['Authorization'] = `Bearer ${authStore.token}`;
      }
      // 处理请求参数
      const method = (request.method ?? 'get').toLowerCase();
      if (config.api.formatRequestFields) {
        if (method === 'get') {
          camelCaseToSnakeCase(request.params);
        } else {
          request.data = request.data ?? {};
          camelCaseToSnakeCase(request.data);
          // 因为有些post接口也有queryString
          camelCaseToSnakeCase(request.params);
        }
      }
      // 处理请求取消
      cancelRequest(request);
      return request;
    },
    onRejected: (err: any) => {
      return Promise.reject(err);
    }
  },
  response: {
    onFulfilled: (response: any) => {
      // 逻辑层请求失败
      const [isFailed, msg] = requestFailed(response);
      if (isFailed) {
        if (canTip(response.config)) {
          // 失败了，可以提示，才提示
          tip(msg);
        }
        return Promise.reject({ code: response.data.code, message: response.data.message });
      }
      // 判断返回值是否是blob格式,是直接返回文件流
      const isBlob = response.data instanceof Blob;
      if (isBlob) return response;
      // 逻辑层请求成功
      const { data } = response['data'];
      // const { success, message } = data || {};

      // /** 在逻辑层判断接口返回的 res.data.success 是否为true，否则直接跳弹窗 */
      // if (success === false) {
      //   tip(message);
      //   return Promise.reject(new Error(message));
      // }

      let parsedData = data;
      // // 有加密则解密
      if (config.encrypt && data) {
        try {
          parsedData = JSON.parse(decode(data, response));
        } catch (e) {
          parsedData = {};
        }
      }

      if (config.api.formatResponseFields) {
        // 将下划线命名的属性转换为驼峰命名
        snakeCaseToCamelCase(parsedData);
      }

      response.data = parsedData;
      return response;
    },
    onRejected: (err: any) => {
      // 网络层请求失败
      if (!err.response) {
        return Promise.reject(err);
      }

      // 服务端返回错误
      const code = getErrorCode(err);
      if (canTip(err.response.config)) {
        switch (code) {
          case 401:
            tip('登录过期，请重新登录');
            break;
          case 402:
            tip('当前为体验版，升级为旗舰版，享受更多权益');
            break;
          case 403:
            tip('您没有该功能权限，请联系管理员');
            break;
          case 404:
            tip('当前路径不存在');
            break;
          case 405:
            tip('请求方法不正确');
            break;
          case 409:
            tip('您的账户已在其他设备登录，若非本人操作，请及时修改密码');
            break;
          case 429:
            tip('请求过于频繁，请稍后再试');
            break;
          case 500:
            tip('内部服务器错误，请稍后再试');
            break;
          default:
            tip(err.response.data.message || '网络不佳，请刷新后重试');
            break;
        }
      }
      if (code === 401 || code === 409) {
        controllerList.forEach((controller) => controller.abort());
        appLoginOutHandler();
      }

      return Promise.reject(err);
    }
  }
};

export default formatHandler;
